
#ifndef __SEQUENTIAL_MINIMAL_OPTIMIZATION_INCLUDED
#define __SEQUENTIAL_MINIMAL_OPTIMIZATION_INCLUDED

#include "../SVMData.h"

class CSMOonGPU {
protected:
	float m_f_C;
	float m_f_tolerance;
	float m_f_epsilon;
	// learning config

	bool m_b_linear_kernel;
	float m_f_two_sigma_squared; // rbf kernel
	// kernel config

	CUdeviceptr m_dp_alpha_list;
	float *m_p_alpha_list; // need alphas on CPU side sometimes (calculated on CPU actually, updates to GPU after each step)
	CUdeviceptr m_dp_w_list; // linear kernels only
	float m_f_offset;
	// output

	CUdeviceptr m_dp_error_cache;
	float *m_p_error_cache; // need error cache on CPU side sometimes (updates after each step)
	CUdeviceptr m_dp_precomputed_kernel; // n_point_num x n_point_num
	float *m_p_precomputed_kernel; // needed on CPU by f_KernelFunc() when deciding which lagrange coeffs to optimize (never updates, calculated once at startup)
	size_t m_n_point_num; // for 2D access to m_p_precomputed_kernel
	
	CUdeviceptr m_dp_reduction_list, m_dp_reduction_helper;
	float *m_p_reduction_list;
	// intermediate

	CMerseneTwister m_random;

	CUdeviceptr m_dp_dense_targets; // need targets on GPU side (never updates, loaded once at startup)
	CUdeviceptr m_dp_dense_points; // need points on GPU side (never updates, loaded once at startup)
	size_t m_n_dimension_num; // for 2D access to m_dp_dense_points
	// dense input (GPU-side)

	CDataModel *m_p_data;
	// input

	CUmodule m_h_module;
	CUfunction h_precalc_dp, h_precalc_rbf_o, h_precalc_rbf_d;
	CUfunction h_update_w, h_update_err, h_eval_nl_kernel;
	CUfunction p_kernel_reduction[10], p_simple_reduction[10];
	
	CUdeviceptr dp_results, dp_results_tmp;

public:
	CSMOonGPU(CUmodule h_module);
	~CSMOonGPU();

	double f_ErrorRate() const;
	float f_LearnedFunc(size_t n_point) const;

	bool SetModel(CDataModel *p_data, bool b_use_linear_kernel);
	bool Train(float f_C, float f_tolerance, float f_epsilon,
		size_t n_max_iters = 15000, bool b_verbose = false);

protected:
	inline float f_KernelFunc(size_t i, size_t j) const;
	float f_learned_func_linear_dense(size_t k) const;
	float f_learned_func_nonlinear(size_t k) const;
	inline int n_Target(size_t i) const;
	int ExamineExample(int i2);
	bool TakeStep(int i1, int i2);
	static inline int n_NearestGEquaPo2(int n);
};


#endif //__SEQUENTIAL_MINIMAL_OPTIMIZATION_INCLUDED
